/**
 * Copyright (C) 2011 GreenSoft S.A.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *        http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ar.com.greensoft.neosystem.dao.jpa;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ejb.Stateless;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Selection;

import org.apache.commons.lang3.StringUtils;

import ar.com.greensoft.neosystem.dao.PersonaFisicaDao;
import ar.com.greensoft.neosystem.dto.PersonaFisicaDto;
import ar.com.greensoft.neosystem.model.PersonaFisica;
import ar.com.greensoft.neosystem.model.PersonaFisica_;
import ar.com.greensoft.neosystem.model.references.Sexo;
import ar.com.greensoft.neosystem.search.SearchFilter;
import ar.com.greensoft.neosystem.search.clientes.PersonaFisicaSearchFilter;
import ar.com.greensoft.neosystem.util.SearchUtil;

/**
 * Java Persistence API Implementation of PersonaFisica Data Access Object Pattern
 * @author Jorge E. Villaverde
 * @date 04/10/2011
 * @version 1.1
 */
@Stateless
public class JpaPersonaFisicaDaoImpl 
	extends JpaPersonaDao<PersonaFisica, PersonaFisicaDto> 
	implements PersonaFisicaDao {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Override
	protected Class<PersonaFisica> getEntityClazz() {
		return PersonaFisica.class;
	}

	@Override
	protected String getFindByCuitQueryName() {
		return PersonaFisica.FIND_BY_CUIT_QUERY_NAME;
	}

	@Override
	protected String getFindByTipoNroDocumentoQueryName() {
		return PersonaFisica.FIND_BY_TIPO_NRO_DOC_QUERY_NAME;
	}
	
	@Override
	protected Expression<Boolean> createWhereFromSearchFilter(
			SearchFilter searchFilter, Root<PersonaFisica> root) {
		if(searchFilter == null || !searchFilter.hasFilter())
			return null;
		
		PersonaFisicaSearchFilter filter = (PersonaFisicaSearchFilter)searchFilter;
		CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
		Predicate predicate = null;
		
		if(filter.getTipoDocumento() != null){
			Predicate predTipoDoc = criteriaBuilder.equal(
					root.get(PersonaFisica_.tipoDocumento), filter.getTipoDocumento());
			predicate = appendAndPredicate(predicate, predTipoDoc);			
		}
		
		if(filter.getNumeroDocumento() != null && filter.getNumeroDocumento() > 0){
			Predicate predNroDoc = criteriaBuilder.equal(
					root.get(PersonaFisica_.numeroDocumento), filter.getNumeroDocumento());
			predicate = appendAndPredicate(predicate, predNroDoc);
		}

		if(!StringUtils.isBlank(filter.getApellido1())){
			String likeString = SearchUtil.likeString(filter.getApellido1()).toUpperCase();
			Predicate predApellido1 = criteriaBuilder.like(criteriaBuilder.upper(root.get(PersonaFisica_.apellido1)), likeString);
			predicate = appendAndPredicate(predicate, predApellido1);			
		}
		if(!StringUtils.isBlank(filter.getApellido2())){
			String likeString = SearchUtil.likeString(filter.getApellido2()).toUpperCase();
			Predicate predApellido2 = criteriaBuilder.like(criteriaBuilder.upper(root.get(PersonaFisica_.apellido2)), likeString);
			predicate = appendAndPredicate(predicate, predApellido2);			
		}
		if(!StringUtils.isBlank(filter.getPrimerNombre())){
			String likeString = SearchUtil.likeString(filter.getPrimerNombre()).toUpperCase();
			Predicate predPrimerNombre = criteriaBuilder.like(criteriaBuilder.upper(root.get(PersonaFisica_.primerNombre)), likeString);
			predicate = appendAndPredicate(predicate, predPrimerNombre);			
		}
		if(!StringUtils.isBlank(filter.getSegundoNombre())){
			String likeString = SearchUtil.likeString(filter.getSegundoNombre()).toUpperCase();
			Predicate predSegundoNombre = criteriaBuilder.like(criteriaBuilder.upper(root.get(PersonaFisica_.segundoNombre)), likeString);
			predicate = appendAndPredicate(predicate, predSegundoNombre);			
		}
		return predicate;
	}

	@Override
	protected String getFindByNameNamedQuery() {
		return PersonaFisica.FIND_BY_NAME_QUERY_NAME;
	}
	
	@Override
	protected List<Order> createOrders(Root<PersonaFisica> root) {
		CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
		List<Order> orders = new ArrayList<Order>();
		orders.add(builder.asc(root.get(PersonaFisica_.apellido1)));
		orders.add(builder.asc(root.get(PersonaFisica_.apellido2)));
		orders.add(builder.asc(root.get(PersonaFisica_.primerNombre)));
		orders.add(builder.asc(root.get(PersonaFisica_.segundoNombre)));
		return orders;
	}

	@Override
	protected Class<PersonaFisicaDto> getDtoClazz() {
		return PersonaFisicaDto.class;
	}

	@Override
	protected Selection<? extends PersonaFisicaDto> createDtoBuilder(CriteriaBuilder builder, Root<PersonaFisica> root) {
		return builder.construct(PersonaFisicaDto.class,
				root.get(PersonaFisica_.id),
				root.get(PersonaFisica_.tipoDocumento),
				root.get(PersonaFisica_.numeroDocumento),
				root.get(PersonaFisica_.cuit),
				root.get(PersonaFisica_.apellido1),
				root.get(PersonaFisica_.apellido2),
				root.get(PersonaFisica_.primerNombre),
				root.get(PersonaFisica_.segundoNombre),
				root.get(PersonaFisica_.sexo),
				root.get(PersonaFisica_.fechaNacimiento));
	}

	@Override
	protected Map<String, Expression<?>> getExpressionMap(Root<PersonaFisica> root) {
		if(expressionMap == null){
			expressionMap = new HashMap<String, Expression<?>>();
			expressionMap.put("tipoDocumento", root.get(PersonaFisica_.tipoDocumento));
			expressionMap.put("numeroDocumento", root.get(PersonaFisica_.numeroDocumento));
			expressionMap.put("cuit", root.get(PersonaFisica_.cuit));
			expressionMap.put("apellido1", root.get(PersonaFisica_.apellido1));
			expressionMap.put("apellido2", root.get(PersonaFisica_.apellido2));
			expressionMap.put("primerNombre", root.get(PersonaFisica_.primerNombre));
			expressionMap.put("segundoNombre", root.get(PersonaFisica_.segundoNombre));
			expressionMap.put("sexo", root.get(PersonaFisica_.sexo));
			expressionMap.put("fechaNacimiento", root.get(PersonaFisica_.fechaNacimiento));
		}
		return expressionMap;
	}

	@Override
	public List<PersonaFisica> findBySexo(Sexo sexo) {
		if(logger.isTraceEnabled())
			logger.trace("Returning entity of type: " + getEntityClazz().getSimpleName() + "\twith sexo: " + sexo);

		TypedQuery<PersonaFisica> query = getEntityManager().createNamedQuery(
				PersonaFisica.FIND_BY_SEXO_QUERY_NAME,
				PersonaFisica.class);
		
		query.setParameter("sexo", sexo);
		
		return query.getResultList();
	}
}
